package com.km.netty.handler;

import cn.hutool.core.util.EnumUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.StaticLog;
import com.km.netty.enums.WSReqTypeEnum;
import com.km.netty.vo.req.WSBaseReq;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ConcurrentHashMap;

/**
 * Netty WebSocket 服务器处理器
 * 处理 WebSocket 连接、消息传输、心跳检测、异常捕获等
 */
@Slf4j
@ChannelHandler.Sharable  // 标记该处理器可以被多个 Channel 共享
public class NettyWebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    /**
     * 存储在线的 WebSocket 连接
     * Key: Channel ID
     * Value: Channel 对象
     */
    private static final ConcurrentHashMap<String, Channel> ONLINE_WS_MAP = new ConcurrentHashMap<>();

    /**
     * 1️⃣ 客户端连接时触发
     * - 在 Channel 初始化时被调用
     * - 记录连接信息，并将连接存入在线映射表
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        super.handlerAdded(ctx);
        log.info("1️⃣handlerAdded->连接创建,ctx.name:{},ctx.channel:{},ctx.channel.id:{}", ctx.name(), ctx.channel(), ctx.channel().id());
        ONLINE_WS_MAP.put(ctx.channel().id().asLongText(), ctx.channel());
    }

    /**
     * 2️⃣ 连接建立并处于活动状态时触发
     * - 代表 WebSocket 连接已经建立
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        log.info("2️⃣channelActive->连接已激活, ctx.name:{},ctx.channel:{},ctx.channel.id:{}", ctx.name(), ctx.channel(), ctx.channel().id());
    }

    /**
     * 3️⃣ 处理 WebSocket 事件（包括心跳检测 & 握手完成事件）
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        super.userEventTriggered(ctx, evt);
        log.info("3️⃣userEventTriggered-->用户事件触发");
        //心跳检查
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            // 读空闲 (还有写空闲,和读写空闲)
            if (idleStateEvent.state() == IdleState.READER_IDLE) {
                log.warn("3️⃣1️⃣30s 未收到客户端数据，关闭连接, channelId: {}", ctx.channel().id().asLongText());
                userOffLine(ctx);
            }
        }
        //握手事件
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
            log.info("3️⃣2️⃣WebSocket 握手成功, channelId: {}", ctx.channel().id().asLongText());
        }
        log.info("3️⃣userEventTriggered-->用户事件触发重复");
    }

    /**
     * 4️⃣ 读取 WebSocket 消息
     * 处理来自客户端的消息
     * 这里采用广播模式，将消息发送给所有在线用户
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        log.info("4️⃣️channelRead0-->通道读取0");
        log.info("4️⃣channelRead0--msg-->{}", msg.text());
        log.info("4️⃣channelRead0 消息, channelId: {}, 内容: {}", ctx.channel().id().asLongText(), msg.text());

        ONLINE_WS_MAP.entrySet().forEach(u -> {
            log.info("4️⃣channelRead0 消息, channelId: {}, 发送内容: {}", ctx.channel().id().asLongText(), msg.text());
            u.getValue().writeAndFlush(new TextWebSocketFrame(msg.text()));
        });

        // 将请求类型转化为对象
        if (JSONUtil.isTypeJSON(msg.text())){
            WSBaseReq wsBaseReq = JSONUtil.toBean(msg.text(), WSBaseReq.class);
            switch (EnumUtil.getBy(WSReqTypeEnum::ordinal, wsBaseReq.getType())) {
                case LOGIN:
                    StaticLog.info("登录请求进来了");
                    break;
                case HEARTBEAT:
                    StaticLog.info("心跳包");
                    break;
                case AUTHORIZE:
                    StaticLog.info("登录认证");
                    break;
                default:
                    break;

            }
        }else {
            ctx.writeAndFlush(new TextWebSocketFrame("输入格式有误,请输入正确的格式"));
        }
    }


    /**
     * 5️⃣连接断开（Channel 变为非活动状态时触发）
     * - 服务器主动关闭或客户端断开连接时触发
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        log.info("5️⃣channelInactive-->连接断开");
        ctx.channel().close();
    }


    /**
     * 6️⃣处理客户端断开连接（Channel 被移除时触发）
     * - `handlerRemoved()` 只有在 `channelInactive()` 之后才会被调用
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        super.handlerRemoved(ctx);
        log.info("6️⃣handlerRemoved-->处理程序已删除");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        log.warn("7️⃣⚠️channelId: {}, 异常信息: {}", ctx.channel().id().asLongText(), cause.getMessage());
        ctx.channel().close();
    }


    /**
     * 处理客户端离线
     * - 关闭 Channel 并移除映射表中的连接
     */
    private void userOffLine(ChannelHandlerContext ctx) {
        String channelId = ctx.channel().id().asLongText();
        log.info("🔌 关闭连接, channelId: {}", channelId);
        ONLINE_WS_MAP.remove(channelId);
        ctx.channel().close();
    }
}
